/*
 * FaceCat图形通讯框架
 * 著作权编号:2015SR229355+2020SR0266727
 * 上海卷卷猫信息技术有限公司
 */

#include "../../stdafx.h"
#include "../../include/core/FCNative.h"

namespace FaceCat{
	FCView* FCNative::findView(const FCPoint& mp, ArrayList<FCView*> *views){
		int size = (int)views->size();
		for(int i = size - 1; i >= 0; i--){
			FCView *view = views->get(i);
			if(view->isVisible()){
				bool hasPoint = view->containsPoint(mp);
                if (hasPoint)
                {
                    ArrayList<FCView*> subViews;
                    getSortedViews(view, &subViews);
                    FCView *subView = findView(mp, &subViews);
                    subViews.clear();
                    if (subView)
                    {
                        return subView;
                    }
                    return view;
                }
			}
		}
		return 0;
	}

	FCView* FCNative::findView(const String& name, ArrayList<FCView*> *views){
		for(int c = 0; c < views->size(); c++){
			FCView *view = views->get(c);
			if(view->getName() == name){
				return view;
			}
			else{
				ArrayList<FCView*> subViews = view->m_views;
				if(subViews.size() > 0){
					FCView *fView = findView(name, &subViews);
					if(fView){
						return fView;
					}
				}
			}
		}
		return 0;
	}

	FCView* FCNative::findPreviewsView(FCView *view){
		if(view->allowPreviewsEvent()){
			return view;
		}
		else{
			FCView *parent = view->getParent();
			if(parent){
				return findPreviewsView(parent);
			}
			else{
				return view;
			}
		}
	}

	FCView* FCNative::findWindow(FCView *view){
		if(view->isWindow()){
			return view;
		}
		else{
			FCView *parent = view->getParent();
			if(parent){
				return findWindow(parent);
			}
			else{
				return view;
			}
		}
	}

	float FCNative::getPaintingOpacity(FCView *view){
	    float opacity = view->getOpacity();
        FCView *parent = view->getParent();
        if (parent){
            opacity *= getPaintingOpacity(parent);
        }
        else{
            opacity *= m_opacity;
        }
        return opacity;
	}

	bool FCNative::getSortedViews(FCView *parent, ArrayList<FCView*> *sortedViews){
        ArrayList<FCView*> views;
        if (parent){
			views = parent->m_views;
        }
        else{
            views = m_views;
        }
		int viewSize = views.size();
        int index = 0;
        for (int i = 0; i < viewSize; i++) {
            FCView *view = views.get(i);
            if (view->isVisible()) {
                if (view->isTopMost()) {
                    sortedViews->add(view);
                }
                else {
					sortedViews->insert(index, view);
                    index++;
                }
            }
        }
		return sortedViews->size() > 0;
	}

	void FCNative::getTabStopViews(FCView *view, ArrayList<FCView*> *tabStopViews){
		ArrayList<FCView*> views = view->m_views;
		for(int c = 0; c < views.size(); c++){
			FCView *subView = views.get(c);
			if (!subView->isWindow()){
				if (subView->isEnabled() && subView->isTabStop()){
                    tabStopViews->add(subView);
                }
                getTabStopViews(subView, tabStopViews);
            }
		}
	}

	bool FCNative::isPaintEnabled(FCView *view){
	    if (view->isEnabled()){
            FCView *parent = view->getParent();
            if (parent){
                return isPaintEnabled(parent);
            }
            else{
                return true;
            }
        }
        else{
            return false;
        }
	}

	void FCNative::renderView(const FCRect& rect, FCView *view, float opacity){
		FCRect destRect;
		FCPoint cPoint = clientPoint(view);
		int clx = cPoint.x;
		int cly = cPoint.y;
		FCRect bounds = {clx, cly, clx + view->getWidth(), cly + view->getHeight()};
		if (view->useRegion()){
			FCRect clipRect = view->getRegion();
			bounds.left += clipRect.left;
			bounds.top += clipRect.top;
			bounds.right = bounds.left + clipRect.right - clipRect.left;
			bounds.bottom = bounds.top + clipRect.bottom - clipRect.top;
		}
		if (view->isVisible() && m_host->getIntersectRect(&destRect, &rect, &bounds) > 0){
			FCRect clipRect = {destRect.left - clx, destRect.top - cly,
				destRect.right - clx, destRect.bottom - cly};
			float newOpacity = view->getOpacity() * opacity;
			setPaint(clx, cly, clipRect, newOpacity);
			FCSize oldSize = view->getSize();
			bool flag = view->onPrePaint(m_paint, clipRect);
			FCSize newSize = view->getSize();
			if(oldSize.cx != newSize.cx || oldSize.cy != newSize.cy){
				bounds.left  = clx;
				bounds.top = cly;
				bounds.right = clx + view->getWidth();
				bounds.bottom = cly + view->getHeight();
				if (view->useRegion()){
					FCRect clipRect2 = view->getRegion();
					bounds.left += clipRect2.left;
					bounds.top += clipRect2.top;
					bounds.right = bounds.left + clipRect2.right - clipRect2.left;
					bounds.bottom = bounds.top + clipRect2.bottom - clipRect2.top;
				}
				if(m_host->getIntersectRect(&destRect, &rect, &bounds) > 0){
					clipRect.left = destRect.left - clx;
					clipRect.top = destRect.top - cly;
					clipRect.right = destRect.right - clx;
					clipRect.bottom = destRect.bottom - cly;
					setPaint(clx, cly, clipRect, newOpacity);

				}else{
					flag = false;
					return;
				}
			}
			if(!flag){
				view->onPaint(m_paint, clipRect);
			}

			ArrayList<FCView*> views = view->m_views;
            int viewSize = views.size();
            ArrayList<FCView*> topViews;
            for (int i = 0; i < viewSize; i++)
            {
                FCView *subView = views.get(i);
                if (subView->isVisible())
                {
                    if (subView->isTopMost())
                    {
                        topViews.add(subView);
                        //sortedViews.add(view);
                    }
                    else
                    {
                        renderView(destRect, subView, newOpacity);
                    }
                }
            }
            int topViewsSize = topViews.size();
            for (int i = 0; i < topViewsSize; i++)
            {
                renderView(destRect, topViews.get(i), newOpacity);
            }
            topViews.clear();

			setPaint(clx, cly, clipRect, newOpacity);
			if(!flag){
				view->onPaintBorder(m_paint, clipRect);
			}
		}
	}

	void FCNative::renderViews(const FCRect& rect, ArrayList<FCView*> *views, float opacity){
		m_paint->setResourcePath(m_resourcePath);
		for(int c = 0; c < views->size(); c++){
			FCView *view = views->get(c);
			renderView(rect, view, opacity);
		}
	}

	void FCNative::setCursor(FCView *view){
		FCCursors cursor = view->getCursor();
		if(!isPaintEnabled(view)){
			cursor = FCCursors_Arrow;
		}
		if(cursor != getCursor()){
			setCursor(cursor);
		}
	}

	void FCNative::setPaint(int offsetX, int offsetY, const FCRect& clipRect, float opacity){
		FCPoint offset = {offsetX, offsetY};
		m_paint->setOffset(offset);
        m_paint->setClip(clipRect);
		m_paint->setOpacity(opacity);
	}

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

	FCNative::FCNative(){
		m_allowScaleSize = false;
		m_size.cx = 0;
		m_size.cy = 0;
		m_drawBeginPoint.x = 0;
		m_drawBeginPoint.y = 0;
		m_dragBeginRect.left = 0;
		m_dragBeginRect.top = 0;
		m_dragBeginRect.right = 0;
		m_dragBeginRect.bottom = 0;
		m_draggingView = 0;
		m_dragStartOffset.x = 0;
		m_dragStartOffset.y = 0;
		m_exportingView = 0;
		m_focusedView = 0;
		m_host = 0;
		m_touchDownView = 0;
		m_touchDownPoint.x = 0;
		m_touchDownPoint.y = 0;
		m_touchMoveView = 0;
		m_opacity = 1;
		m_paint = 0;
		m_rotateAngle = 0;
		m_scaleSize.cx = 0;
		m_scaleSize.cy = 0;
		m_lockUpdate = false;
	}

	FCNative::~FCNative(){
		m_draggingView = 0;
		m_exportingView = 0;
		m_focusedView = 0;
		if(m_host){
			delete m_host;
			m_host = 0;
		}
		m_touchDownView = 0;
		m_touchMoveView = 0;
		for(int i = 0; i < m_timers.size(); i++){
			stopTimer(m_timers.getKey(i));
		}
		clearViews();
		if(m_paint){
			delete m_paint;
			m_paint = 0;
		}
	}

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

	bool FCNative::allowScaleSize(){
		return m_allowScaleSize;
	}

	void FCNative::setAllowScaleSize(bool value){
		m_allowScaleSize = value;
	}

	FCCursors FCNative::getCursor(){
		if(m_host){
			return m_host->getCursor();
		}
		return FCCursors_Arrow;
	}

	void FCNative::setCursor(FCCursors value){
		if(m_host){
			m_host->setCursor(value);
		}
	}

	FCView* FCNative::getFocusedView(){
		return m_focusedView;
	}

	void FCNative::setFocusedView(FCView *value){
		if (m_focusedView != value){
            if (m_focusedView){
				FCView *fView = m_focusedView;
				m_focusedView = 0;
                fView->onLostFocus();
            }
            m_focusedView = value;
            if (m_focusedView){
                m_focusedView->onGotFocus();
            }
        }
	}

	FCHost* FCNative::getHost(){
		return m_host;
	}

	void FCNative::setHost(FCHost *value){
		if(m_host){
			delete m_host;
		}
		m_host = value;
	}

	FCView* FCNative::getHoveredView(){
		return m_touchMoveView;
	}

	FCPoint FCNative::getTouchPoint(){
		FCPoint mp = {0};
		if(m_host){
			mp = m_host->getTouchPoint();
		}
		return mp;
	}

	float FCNative::getOpacity(){
		return m_opacity;
	}

	void FCNative::setOpacity(float value){
		m_opacity = value;
	}

	FCPaint* FCNative::getPaint(){
		return m_paint;
	}

	void FCNative::setPaint(FCPaint *value){
		if(m_paint){
			delete m_paint;
		}
		m_paint = value;
	}

	FCView* FCNative::getPushedView(){
		return m_touchDownView;
	}

	String FCNative::getResourcePath(){
		return m_resourcePath;
	}

	void FCNative::setResourcePath(const String& value){
		m_resourcePath = value;
	}

	int FCNative::getRotateAngle(){
		return m_rotateAngle;
	}

	void FCNative::setRotateAngle(int value){
		m_rotateAngle = value;
	}

	FCSize FCNative::getScaleSize(){
		return m_scaleSize;
	}

	void FCNative::setScaleSize(FCSize value){
		m_scaleSize = value;
	}

	FCSize FCNative::getSize(){
		return m_size;
	}

	void FCNative::setSize(FCSize value){
		m_size = value;
	}

	//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

	void FCNative::addView(FCView *view){
		view->setNative(this);
		m_views.add(view);
		view->onAdd();
	}

	void FCNative::bringToFront(FCView *view){
		ArrayList<FCView*> views;
		FCView *parent = view->getParent();
		if(parent){
			parent->bringChildToFront(view);
		}
		else{
			if(m_views.size() > 0){
				for(int c = 0; c < m_views.size(); c++){
					if(view == m_views.get(c)){
						m_views.removeAt(c);
						break;
					}
				}
				m_views.add(view);
			}
		}
	}

	void FCNative::cancelDragging(){
		if(m_draggingView){
			m_draggingView->setBounds(m_dragBeginRect);
			FCView *draggingView = m_draggingView;
			m_draggingView = 0;
			draggingView->onDragEnd();
			FCView *parent = draggingView->getParent();
			if (parent){
                parent->invalidate();
            }
            else{
                invalidate();
            }
		}
	}

	void FCNative::clearViews(){
		while((int)m_views.size() > 0){
            FCView *view = m_views.get(0);
            m_views.removeAt(0);
            view->onRemove();
            delete view;
        }
		m_touchDownView = 0;
        m_touchMoveView = 0;
	}

	void FCNative::clearViewState(FCView *view){
        if(view == m_draggingView){
            m_draggingView = 0;
        }
        if(view == m_focusedView){
            m_focusedView = 0;
        }
        if(view == m_touchDownView){
            m_touchDownView = 0;
        }
        if(view == m_touchMoveView){
            m_touchMoveView = 0;
        }
        ArrayList<int> removeTimers;
        for(int i = 0; i < m_timers.size(); i++){
            if(m_timers.getValue(i) == view){
                removeTimers.add(m_timers.getKey(i));
            }
        }
        for(int i = 0; i < removeTimers.size(); i++){
            stopTimer(removeTimers.get(i));
		}
        for(int i = 0; i < view->m_views.size(); i++){
            clearViewState(view->m_views.get(i));
        }
    }

	int FCNative::clientX(FCView *view){
		if (view){
			FCView *parent = view->getParent();
			int cLeft = view->getLeft();
			if(view == m_exportingView){
				cLeft = 0;
				return cLeft;
			}
            if (parent){
				return cLeft - (view->displayOffset() ? parent->getDisplayOffset().x : 0) +  clientX(parent);
            }
            else{
                return cLeft;
            }
        }
        else{
            return 0;
        }
	}

	int FCNative::clientY(FCView *view){
		if (view){
			FCView *parent = view->getParent();
			int cTop = view->getTop();
			if(view == m_exportingView){
				cTop = 0;
				return cTop;
			}
            if (parent){
				return cTop - (view->displayOffset() ? parent->getDisplayOffset().y : 0) + clientY(parent);
            }
            else{
                return cTop;
            }
        }
        else{
            return 0;
        }
	}

	 FCPoint FCNative::clientPoint(FCView *view){
        if (view)
        {
            FCView *parent = view->getParent();
            int cLeft = view->getLeft();
            int cTop = view->getTop();
            if (parent)
            {
                FCPoint parentClientY = clientPoint(parent);
                if (view->displayOffset())
                {
                    FCPoint displayOffset = parent->getDisplayOffset();
                    FCPoint mp = {cLeft - displayOffset.x + parentClientY.x,
                        cTop - displayOffset.y + parentClientY.y};
					return mp;
                }
                else
                {
                    FCPoint mp = {cLeft + parentClientY.x,
                        cTop + parentClientY.y};
					return mp;
                }
            }
            else
            {
                FCPoint mp = {cLeft, cTop};
				return mp;
            }
        }
        else
        {
            FCPoint mp = {0, 0};
			return mp;
        }
    }

	bool FCNative::containsView(FCView *view){
		if(m_views.size() > 0){
			for(int c = 0; c < m_views.size(); c++){
				if(view == m_views.get(c)){
					return true;
				}
			}
		}
		return false;
	}

	void FCNative::exportToImage(const String& exportPath){
		exportToImage(exportPath, 0);
	}

    void FCNative::exportToImage(const String& exportPath, FCView *view){
        m_exportingView = view;
        if (view){
            ArrayList<FCView*> views;
            views.add(view);
			FCRect rect = {0, 0, view->getWidth(), view->getHeight()};
            m_paint->beginExport(exportPath, rect);
            renderViews(rect, &views, getPaintingOpacity(view));
            m_paint->endExport();
        }
        else{
			FCRect rect = {0, 0, m_size.cx, m_size.cy};
            m_paint->beginExport(exportPath, rect);
			ArrayList<FCView*> subViews;
			if(!getSortedViews(view, &subViews)){
				subViews = m_views;
			}
            renderViews(rect, &subViews, m_opacity);
            m_paint->endExport();
        }
        m_exportingView = 0;
	}

	FCView* FCNative::findView(const FCPoint& mp){
		ArrayList<FCView*> subViews;
		if(!getSortedViews(0, &subViews)){
			subViews = m_views;
		}
		return findView(mp, &subViews);
	}

	FCView* FCNative::findView(const FCPoint& mp, FCView *parent){
		ArrayList<FCView*> subViews;
		if(!getSortedViews(parent, &subViews)){
			if(parent){
				subViews = parent->m_views;
			}
			else{
				subViews = m_views;
			}
		}
		return findView(mp, &subViews);
	}

	FCView* FCNative::findView(const String& name){
		return findView(name, &m_views);
	}

	ArrayList<FCView*> FCNative::getViews(){
		return m_views;
	}

	void FCNative::insertView(int index, FCView *view){
		view->setNative(this);
        m_views.insert(index, view);
        view->onAdd();
	}

	void FCNative::invalidate(){
		if(m_host){
			m_host->invalidate();
		}
	}

	void FCNative::invalidate(FCView *view){
		if(m_host){
			int clx = clientX(view);
            int cly = clientY(view);
			FCRect rect = {clx, cly, clx + view->getWidth(), cly + view->getHeight()};
            m_host->invalidate(rect);
		}
	}

	void FCNative::invalidate(const FCRect& rect){
		if(m_host){
			m_host->invalidate(rect);
		}
	}

	bool FCNative::onChar(wchar_t key){
		FCView *focusedView = getFocusedView();
		if(focusedView && isPaintEnabled(focusedView)){
			if(focusedView->isTabStop()){
			FCView *window = findWindow(focusedView);
			if(window){
				if(!(m_host->isKeyPress(VK_CONTROL)
				|| m_host->isKeyPress(VK_MENU)
				|| m_host->isKeyPress(VK_SHIFT))
				&& key == 9 ){
					ArrayList<FCView*> tabStopViews;
					getTabStopViews(window, &tabStopViews);
					int size = (int)tabStopViews.size();
					if (size > 0){
						for (int i = 0; i < size - 1; i++){
							for (int j = 0; j < size - 1 - i; j++){
								FCView *viewLeft = tabStopViews.get(j);
								FCView *viewRight = tabStopViews.get(j + 1);
								if (viewLeft->getTabIndex() > viewRight->getTabIndex()){
									FCView *temp = tabStopViews.get(j + 1);
									tabStopViews.set(j + 1, tabStopViews.get(j));
									tabStopViews.set(j, temp);
								}
							}
						}
						bool change = false;
						FCView *newFocusedView = 0;
						for (int i = 0; i < size; i++){
							FCView *view = tabStopViews.get(i);
							if (focusedView == view){
								if (i < size - 1){
									newFocusedView = tabStopViews.get(i + 1);
								}
								else{
									newFocusedView = tabStopViews.get(0);
								}
								change = true;
								break;
							}
						}
						if (!change){
							newFocusedView = tabStopViews.get(0);
						}
						if (newFocusedView != focusedView){
							newFocusedView->setFocused(true);
							focusedView = newFocusedView;
							focusedView->onTabStop();
							window->invalidate();
							return true;
						}
					}
				}
			}
			}
			focusedView->onChar(key);
		}
		return false;
	}

	void FCNative::onDoubleClick(FCTouchInfo touchInfo){
	    FCView *focusedView = getFocusedView();
        if (focusedView && isPaintEnabled(focusedView)){
            FCPoint mp = getTouchPoint();
            int clx = clientX(focusedView);
            int cly = clientY(focusedView);
			FCPoint cmp = {mp.x - clx, mp.y - cly};
			FCTouchInfo newTouchInfo = touchInfo;
			newTouchInfo.m_firstPoint = cmp;
			newTouchInfo.m_secondPoint = cmp;
            focusedView->onDoubleClick(newTouchInfo);
        }
	}

	void FCNative::onKeyDown(char key){
		FCView *focusedView = getFocusedView();
		if(focusedView && isPaintEnabled(focusedView)){
			focusedView->onKeyDown(key);
		}
	}

	void FCNative::onKeyUp(char key){
		FCView *focusedView = getFocusedView();
		if(focusedView && isPaintEnabled(focusedView)){
			focusedView->onKeyUp(key);
		}
	}

	void FCNative::onTouchDown(FCTouchInfo touchInfo){
		m_draggingView = 0;
        m_touchDownView = 0;
		FCPoint mp = getTouchPoint();
		m_touchDownPoint = mp;
		ArrayList<FCView*> subViews;
		if(!getSortedViews(0, &subViews)){
			subViews = m_views;
		}
        FCView *view = findView(mp, &subViews);
		if(view){
			FCView *window = findWindow(view);
			if(window && window->isWindow()){
				window->bringToFront();
			}
			if(isPaintEnabled(view)){
				int clx = clientX(view);
				int cly = clientY(view);
				FCPoint cmp = {mp.x - clx, mp.y - cly};
				FCView *focusedView = getFocusedView();
				m_touchDownView = view;
				if (focusedView == getFocusedView()){
					if(view->canFocus()){
						setFocusedView(view);
					}
				}
				FCTouchInfo newTouchInfo = touchInfo;
				newTouchInfo.m_firstPoint = mp;
				newTouchInfo.m_secondPoint = mp;
				if (onPreviewsTouchEvent(L"ontouchdown", m_touchDownView, newTouchInfo)){
					m_touchDownView = 0;
                    return;
                }
				newTouchInfo.m_firstPoint = cmp;
				newTouchInfo.m_secondPoint = cmp;
				if(m_touchDownView){
					m_touchDownView->onTouchDown(newTouchInfo);
				}
				if(m_touchDownView){
					m_touchDownView->onDragReady(&m_dragStartOffset);
				}
			}
		}
	}

	void FCNative::onTouchLeave(FCTouchInfo touchInfo){
		if (m_touchMoveView && isPaintEnabled(m_touchMoveView)){
			FCPoint mp = getTouchPoint();
			FCPoint cmp = {mp.x - clientX(m_touchMoveView), mp.y - clientY(m_touchMoveView)};
			FCView *touchMoveView = m_touchMoveView;
			m_touchMoveView = 0;
			FCTouchInfo newTouchInfo = touchInfo;
			newTouchInfo.m_firstPoint = mp;
			newTouchInfo.m_secondPoint = mp;
			if (onPreviewsTouchEvent(L"ontouchleave", m_touchDownView, newTouchInfo)){
                return;
            }
			newTouchInfo.m_firstPoint = cmp;
			newTouchInfo.m_secondPoint = cmp;
            touchMoveView->onTouchLeave(newTouchInfo);
        }
	}

	void FCNative::onTouchMove(FCTouchInfo touchInfo){
		FCPoint mp = getTouchPoint();
		if(m_touchDownView){
			FCTouchInfo newTouchInfo = touchInfo;
			newTouchInfo.m_firstPoint = mp;
			newTouchInfo.m_secondPoint = mp;
			if (onPreviewsTouchEvent(L"ontouchmove", m_touchDownView, newTouchInfo)){
                return;
            }
			FCPoint cmp = {mp.x - clientX(m_touchDownView), mp.y - clientY(m_touchDownView)};
			newTouchInfo.m_firstPoint = cmp;
			newTouchInfo.m_secondPoint = cmp;
			m_touchDownView->onTouchMove(newTouchInfo);
			setCursor(m_touchDownView);
			if (m_touchDownView->allowDrag() && touchInfo.m_firstTouch && touchInfo.m_clicks == 1){
				if (abs(mp.x - m_touchDownPoint.x) > m_dragStartOffset.x
                        || abs(mp.y - m_touchDownPoint.y) > m_dragStartOffset.y){
					if(m_touchDownView->onDragBegin()){
						m_dragBeginRect = m_touchDownView->getBounds();
						m_drawBeginPoint = m_touchDownPoint;
						m_draggingView = m_touchDownView;
						m_touchDownView = 0;
						FCView *parent = m_draggingView->getParent();
						if (parent){
							parent->invalidate();
						}
						else{
							invalidate();
						}
					}
				}
			}
		}
		else if(m_draggingView){
			FCView *draggingView = m_draggingView;
            int offsetX = mp.x - m_drawBeginPoint.x;
            int offsetY = mp.y - m_drawBeginPoint.y;
            FCRect newBounds = m_dragBeginRect;
            newBounds.left += offsetX;
            newBounds.top += offsetY;
            newBounds.right += offsetX;
            newBounds.bottom += offsetY;
            draggingView->setBounds(newBounds);
            draggingView->onDragging();
			FCView *parent = draggingView->getParent();
            if (parent){
                parent->invalidate();
            }
            else{
                invalidate();
            }
		}
		else{
			ArrayList<FCView*> subViews;
			if(!getSortedViews(0, &subViews)){
				subViews = m_views;
			}
			FCView *view = findView(mp, &subViews);
			FCTouchInfo newTouchInfo = touchInfo;
			newTouchInfo.m_firstPoint = mp;
			newTouchInfo.m_secondPoint = mp;
			if(view){
				if (onPreviewsTouchEvent(L"ontouchmove", view, newTouchInfo)){
                    return;
                }
			}
			if(m_touchMoveView != view){
				if(m_touchMoveView && isPaintEnabled(m_touchMoveView)){
					if(!m_touchDownView){
						FCPoint cmp = {mp.x - clientX(m_touchMoveView), mp.y - clientY(m_touchMoveView)};
						FCView *touchMoveView = m_touchMoveView;
						m_touchMoveView = 0;
						newTouchInfo.m_firstPoint = cmp;
						newTouchInfo.m_secondPoint = cmp;
						touchMoveView->onTouchLeave(newTouchInfo);
					}
				}
				if(view && isPaintEnabled(view)){
					if(!m_touchDownView){
						FCPoint cmp = {mp.x - clientX(view), mp.y - clientY(view)};
						m_touchMoveView = view;
						newTouchInfo.m_firstPoint = cmp;
						newTouchInfo.m_secondPoint = cmp;
						view->onTouchEnter(newTouchInfo);
						view->onTouchMove(newTouchInfo);
						setCursor(view);
					}
				}
			}
			else{
				if(view && isPaintEnabled(view)){
					FCPoint cmp = {mp.x - clientX(view), mp.y - clientY(view)};
					m_touchMoveView = view;
					FCTouchInfo newTouchInfo = touchInfo;
					newTouchInfo.m_firstPoint = cmp;
					newTouchInfo.m_secondPoint = cmp;
					view->onTouchMove(newTouchInfo);
					setCursor(view);
				}
			}
		}
	}

	void FCNative::onTouchUp(FCTouchInfo touchInfo){
		FCPoint mp = getTouchPoint();
		if(m_touchDownView){
			ArrayList<FCView*> subViews;
			if(!getSortedViews(0, &subViews)){
				subViews = m_views;
			}
			FCView *touchDownView = m_touchDownView;
			FCTouchInfo newTouchInfo = touchInfo;
			newTouchInfo.m_firstPoint = mp;
			newTouchInfo.m_secondPoint = mp;
			if (onPreviewsTouchEvent(L"ontouchup", touchDownView, newTouchInfo)){
                return;
            }
			if(m_touchDownView){
				FCView *view = findView(mp, &subViews);
				FCPoint cmp = {mp.x - clientX(m_touchDownView), mp.y - clientY(m_touchDownView)};
				newTouchInfo.m_firstPoint = cmp;
				newTouchInfo.m_secondPoint = cmp;
				if(view && view == m_touchDownView){
					m_touchDownView->onClick(newTouchInfo);
				}
				else{
					m_touchMoveView = 0;
				}
				if(m_touchDownView){
					touchDownView = m_touchDownView;
					m_touchDownView = 0;
					touchDownView->onTouchUp(newTouchInfo);
				}
			}
		}
		else if (m_draggingView){
			ArrayList<FCView*> subViews;
			if(!getSortedViews(0, &subViews)){
				subViews = m_views;
			}
			FCPoint cmp = {mp.x - clientX(m_touchDownView), mp.y - clientY(m_touchDownView)};
			FCView *draggingView = m_draggingView;
			m_draggingView = 0;
			FCTouchInfo newTouchInfo = touchInfo;
			newTouchInfo.m_firstPoint = mp;
			newTouchInfo.m_secondPoint = mp;
			if (onPreviewsTouchEvent(L"ontouchup", draggingView, newTouchInfo)){
                return;
            }
			newTouchInfo.m_firstPoint = cmp;
			newTouchInfo.m_secondPoint = cmp;
			draggingView->onTouchUp(newTouchInfo);
            draggingView->onDragEnd();
			FCView *parent = draggingView->getParent();
			if (parent){
                parent->invalidate();
            }
            else{
                invalidate();
            }
        }
	}

	void FCNative::onTouchWheel(FCTouchInfo touchInfo){
		FCPoint mp = getTouchPoint();
		ArrayList<FCView*> subViews;
		if(!getSortedViews(0, &subViews)){
			subViews = m_views;
		}
        FCView *focusedView = findView(mp, &subViews);
		if(focusedView && isPaintEnabled(focusedView)){
			FCTouchInfo newTouchInfo = touchInfo;
			newTouchInfo.m_firstPoint = mp;
			newTouchInfo.m_secondPoint = mp;
			if (onPreviewsTouchEvent(L"ontouchwheel", focusedView, newTouchInfo)){
                return;
            }
            mp.x -= clientX(focusedView);
            mp.y -= clientY(focusedView);
			newTouchInfo.m_firstPoint = mp;
			newTouchInfo.m_secondPoint = mp;
			focusedView->onTouchWheel(newTouchInfo);
		}
	}

	void FCNative::onPaint(const FCRect& rect){
		ArrayList<FCView*> subViews;
		if(!getSortedViews(0, &subViews)){
			subViews = m_views;
		}
		renderViews(rect, &subViews, m_opacity);
	}

	bool FCNative::onPreviewsKeyEvent(String eventName, char key){
		FCView *focusedView = getFocusedView();
		if(focusedView && isPaintEnabled(focusedView)){
			FCView *window = findWindow(focusedView);
			if(window){
				return window->onPreviewsKeyEvent(eventName, key);
			}
		}
		return false;
	}

	bool FCNative::onPreviewsTouchEvent(String eventName, FCView *view, FCTouchInfo touchInfo){
	    FCView *previewsView = findPreviewsView(view);
        if (previewsView){
			FCPoint mp = touchInfo.m_firstPoint;
            int clx = clientX(previewsView);
            int cly = clientY(previewsView);
			FCPoint wcmp = {mp.x - clx, mp.y - cly};
			touchInfo.m_firstPoint = wcmp;
			touchInfo.m_secondPoint = wcmp;
            if (previewsView->onPreviewsTouchEvent(eventName, touchInfo)){
                return true;
            }
        }
        return false;
	}

	void FCNative::onResize(){
		update();
	}

    void FCNative::onScaling(double scaleFactorX, double scaleFactorY) {
        int viewSize = m_views.size();
        for (int i = 0; i < viewSize; i++) {
            m_views.get(i)->onScaling(scaleFactorX, scaleFactorY);
        }
    }

	void FCNative::onTimer(int timerID){
		if(m_timers.containsKey(timerID)){
            m_timers.get(timerID)->onTimer(timerID);
		}
	}

	void FCNative::removeView(FCView *view){
		clearViewState(view);
		if(view && !view->getParent()){
			for(int c = 0; c < m_views.size(); c++){
				if(m_views.get(c) == view){
					m_views.removeAt(c);
					view->onRemove();
					return;
				}
			}
		}
	}

	void FCNative::sendToBack(FCView *view){
		ArrayList<FCView*> views;
		FCView *parent = view->getParent();
		if(parent){
			parent->sendChildToBack(view);
		}
		else{
			if(m_views.size() > 0){
				for(int c = 0; c < m_views.size(); c++){
					if(m_views.get(c) == view){
						m_views.removeAt(c);
						break;
					}
				}
				m_views.insert(0, view);
			}
		}
	}

	void FCNative::setAlign(ArrayList<FCView*> *views){
		int viewSize = (int)views->size();
         for (int i = 0; i < viewSize; i++){
             FCView *view = views->get(i);
             if (view->displayOffset()){
				 if (view->getAlign() == FCHorizontalAlign_Left && view->getVerticalAlign() == FCVerticalAlign_Top)
                {
                            continue;
                }
                 FCSize parentSize = m_size;
                 FCView *parent = view->getParent();
                 if (parent){
                     if(!(views == &m_views)){
                         parentSize = parent->getSize();
                     }
                 }
                 FCSize size = view->getSize();
                 FCPadding margin = view->getMargin();
				 FCPadding padding(0);
				if(parent){
					padding = parent->getPadding();
				}
                 if (view->getAlign() == FCHorizontalAlign_Center){
                     view->setLeft((parentSize.cx - size.cx) / 2);
                 }
                 else if (view->getAlign() == FCHorizontalAlign_Right){
                     view->setLeft(parentSize.cx - size.cx - margin.right - padding.right);
                 }
                 if (view->getVerticalAlign() == FCVerticalAlign_Bottom){
                     view->setTop(parentSize.cy - size.cy - margin.bottom - padding.bottom);
                 }
                 else if (view->getVerticalAlign() == FCVerticalAlign_Middle){
                     view->setTop((parentSize.cy - size.cy) / 2);
                 }
             }
         }
	}

	void FCNative::setAnchor(ArrayList<FCView*> *views, FCSize oldSize){
		if(oldSize.cx != 0 && oldSize.cy != 0){
			for(int c = 0; c < views->size(); c++){
				FCView *view = views->get(c);
				FCAnchor anchor = view->getAnchor();
				if (anchor.left && anchor.top && !anchor.right && !anchor.bottom)
                {
                    continue;
                }
				FCSize parentSize = m_size;
				FCView *parent = view->getParent();
				if (parent){
					if(!(views == &m_views)){
						parentSize = parent->getSize();
					}
				}
				FCRect bounds = view->getBounds();
				if (anchor.right && !anchor.left)
                {
                    bounds.left = bounds.left + parentSize.cx - oldSize.cx;
                }
                if (anchor.bottom && !anchor.top)
                {
                    bounds.top = bounds.top + parentSize.cy - oldSize.cy;
                }
                if (anchor.right)
                {
                    bounds.right = bounds.right + parentSize.cx - oldSize.cx;
                }
                if (anchor.bottom)
                {
                    bounds.bottom = bounds.bottom + parentSize.cy - oldSize.cy;
                }
				view->setBounds(bounds);
			}
		}
	}

	void FCNative::setDock(ArrayList<FCView*> *views){
        for(int c = 0; c < views->size(); c++){
			FCView *view = views->get(c);
			FCDockStyle dock = view->getDock();
			if (dock != FCDockStyle_None){
				FCSize parentSize = m_size;
				FCView *parent = view->getParent();
				if (parent){
					parentSize = parent->getSize();
				}
				FCPadding padding(0);
				if(parent){
					padding = parent->getPadding();
				}
				FCPadding margin = view->getMargin();
				FCSize cSize = view->getSize();
				FCRect spaceRect = {padding.left + margin.left, padding.top + margin.top, parentSize.cx - padding.right - margin.right, parentSize.cy - padding.bottom - margin.bottom};
                if (dock == FCDockStyle_Bottom)
                {
                    FCRect bounds = {spaceRect.left, spaceRect.bottom - cSize.cy, spaceRect.right, spaceRect.bottom};
                    view->setBounds(bounds);
                }
                else if (dock == FCDockStyle_Fill)
                {
                    FCRect bounds = {spaceRect.left, spaceRect.top, spaceRect.right, spaceRect.bottom};
                    view->setBounds(bounds);
                }
                else if (dock == FCDockStyle_Left)
                {
                    FCRect bounds = {spaceRect.left, spaceRect.top, spaceRect.left + cSize.cx, spaceRect.bottom};
                    view->setBounds(bounds);
                }
                else if (dock == FCDockStyle_Right)
                {
                    FCRect bounds = {spaceRect.right - cSize.cx, spaceRect.top, spaceRect.right, spaceRect.bottom};
                    view->setBounds(bounds);
                }
                else if (dock == FCDockStyle_Top)
                {
                    FCRect bounds = {spaceRect.left, spaceRect.top, spaceRect.right, spaceRect.top + cSize.cy};
                    view->setBounds(bounds);
                }
			}
		}
	}

	void FCNative::startTimer(FCView *view, int timerID, int interval){
		m_timers.put(timerID, view);
		if(m_host){
			m_host->startTimer(timerID, interval);
		}
	}

	void FCNative::stopTimer(int timerID){
		if(m_timers.containsKey(timerID)){
			if(m_host){
				m_host->stopTimer(timerID);
			}
			m_timers.remove(timerID);
		}
	}

	void FCNative::update(){
		if(m_host && !m_lockUpdate){
			FCSize size = m_host->getSize();
			FCSize oldSize = m_size;
			m_size = size;
			if(m_size.cx != 0 && m_size.cy != 0){
				setAlign(&m_views);
				setAnchor(&m_views, oldSize);
				setDock(&m_views);
                int viewsSize = (int)m_views.size();
                for (int i = 0; i < viewsSize; i++){
                    m_views.get(i)->update();
                }
			}
		}
	}

	static int m_changeID = 0;

    void FCNative::addChangeID(){
        m_changeID++;
    }

    int FCNative::getChangeID(){
        return m_changeID;
    }
}